﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.ComponentModel;

namespace giaoxuhaison.Common
{
    public class SortBuilder : ISortBuilder
    {
        private IEntityHelper _entityHelper;

        public SortBuilder(IEntityHelper entityHelper)
        {   
            _entityHelper = entityHelper;
        }

        public List<T> Sort<T>(List<T> source, string sortName, string sortOrder, int rowNumber)
        {
            if (source != null && source.Any() && sortName != string.Empty
                && sortOrder != string.Empty && rowNumber > 0)
            {
                var propertyName = "";
                if (source[0] != null && source[0].GetType().Name.StartsWith("DynamicEntity"))
                {                    
                    propertyName = _entityHelper.GetPropertyNameOfEntityByDisplayName<T>(sortName, source[0]);
                }
                else
                    propertyName = _entityHelper.GetPropertyNameOfEntityByDisplayName<T>(sortName);

                if (propertyName != string.Empty)
                {
                    Comparison<T> comparisonDelegate = CreateComparison<T>(propertyName, sortOrder);

                    source.Sort(comparisonDelegate);
                }
            }

            return source;
        }

        private Comparison<T> CreateComparison<T>(string propertyName, string sortOrder)
        {
            int sortReverser = sortOrder.ToLower().StartsWith("asc") ? 1 : -1;

            return new Comparison<T>(delegate(T x, T y)
            {
                Type propertyType = _entityHelper.GetPropertyType(x.GetType(), propertyName);
                MethodInfo compareToMethod = GetCompareToMethod(propertyType);

                object xSortExpressionValue = x.GetType().GetProperty(propertyName).GetValue(x, null);
                if (xSortExpressionValue == null)
                {
                    xSortExpressionValue = GetDefaultValueOfPropertyType(propertyType);
                }

                object ySortExpressionValue = y.GetType().GetProperty(propertyName).GetValue(y, null);
                if (ySortExpressionValue == null)
                {
                    ySortExpressionValue = GetDefaultValueOfPropertyType(propertyType);
                }

                object result = compareToMethod.Invoke(xSortExpressionValue, new object[] { ySortExpressionValue });

                return sortReverser * Convert.ToInt16(result);
            });
        }

        private int CalculatePositionOfPage<T>(List<T> source, int id, int numberRowPerPage)
        {
            var index = source.FindIndex(x => (int)x.GetType().GetProperty("Id").GetValue(x, null) == id);
            if (index > 0)
            {
                return (int)Math.Ceiling((index + 1) / (numberRowPerPage * 1.0));
            }

            return 1;
        }

        private MethodInfo GetCompareToMethod(Type propertyType)
        {
            return propertyType.GetMethod("CompareTo", new Type[] { propertyType });
        }

        private object GetDefaultValueOfPropertyType(Type propertyType)
        {
            if (propertyType == typeof(string))
            {
                return string.Empty;
            }
            else if (propertyType == typeof(int) || propertyType == typeof(decimal) || propertyType == typeof(float))
            {
                return -99999;
            }

            return null;
        }
    }
}